﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace intelliSys.NankaiUtilities.EventSynchronizer
{
    public abstract class NKUEventSource : ILiveEventSource
    {
        public virtual string Name
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public virtual string Description
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
        public string EventCentralizedListUrl { get; set; }
        public string EventCentralziedListItemXPath { get; set; }
        public string FullStoryNodeXPath { get; set; }
        public string TitleNodeXPath { get; set; }
        public string ImplicitTimeXPath { get; set; }
        public string PageURIVariantFormat { get; set; }
        public int StartingPageIndex { get; set; }
        public string RequestEncoding { get; set; }

        private string BaseAddress;
        internal string GetBaseAddress()
        {
            if (BaseAddress == null)
            {
                Uri uri = new Uri(EventCentralizedListUrl);
                BaseAddress = uri.Scheme + "://" + uri.Host + "/";
            }
            return BaseAddress;
        }

        internal virtual HtmlDocument GetHtmlEventList(int Page)
        {
            try
            {
                string url = "";
                if (PageURIVariantFormat != null)
                    url = string.Format(EventCentralizedListUrl + PageURIVariantFormat, Page);
                else
                    url = EventCentralizedListUrl;
                WebClient wc = new WebClient();
                var htmlDoc = new HtmlDocument();
                htmlDoc.LoadHtml(wc.DownloadString(url));
                return htmlDoc;
            }
            catch
            {
                return null;
            }
        }

        internal virtual IEnumerable<HtmlNode> GetEventNode(HtmlDocument eventList)
        {
            return eventList.DocumentNode.SelectNodes(EventCentralziedListItemXPath);
        }

        internal virtual bool TryParseThenAddCurrentNode(HtmlNode node, LiveEvents eventList)
        {
            HtmlDocument eventHtml = new HtmlDocument();
            var reqAddr = (GetBaseAddress() + node.Attributes["href"].Value);
            WebClient partialReq = new WebClient();

            partialReq.Encoding = Encoding.GetEncoding(RequestEncoding);
            var result = partialReq.DownloadString(reqAddr);
            eventHtml.LoadHtml(result);
            var fullStoryNode = eventHtml.DocumentNode.SelectSingleNode(FullStoryNodeXPath);
            var title = eventHtml.DocumentNode.SelectSingleNode(TitleNodeXPath).InnerText.Trim();
            string implicitTimeResult = DateTime.Now.Year.ToString();
            if (ImplicitTimeXPath != null)
            {
                var implicitTime = eventHtml.DocumentNode.SelectSingleNode(ImplicitTimeXPath).InnerText;
                implicitTimeResult = Regex.Match(implicitTime, "\\d{4}").Value;
            }
            LiveEvent liveEvent = new LiveEvent();
            StringBuilder standarizedTimeStringBuilder = new StringBuilder();
            bool CriticalTerminationFlag = false;
            liveEvent.Description = string.Format("This link is prefiexed by tool:{0}\r\n{1}", reqAddr, fullStoryNode.InnerText);
            liveEvent.Title = title;
            liveEvent.Link = reqAddr;
            liveEvent.EventSource = this;
            if ("http://sms.nankai.edu.cn//html/kydt/xsjl01/1230.html" == reqAddr)
            {
                Thread.CurrentThread.Name = "NonSTA";
            }
            for (int i = 0; i < fullStoryNode.ChildNodes.Count; i++)
            {
                var currentRun = fullStoryNode.ChildNodes[i].InnerText.Trim().Replace(" ", "").Replace("&nbsp;", "");
                if (currentRun.Contains("时间") || currentRun.Contains("日期"))
                {
                    bool MorningModifier = false, AfternoonModifier = false;
                    var preliminaryTime = currentRun;
                    if (preliminaryTime.Contains("上午"))
                    {
                        MorningModifier = true;
                        preliminaryTime = preliminaryTime.Replace("上午", " ");
                    }
                    if (preliminaryTime.Contains("下午"))
                    {
                        AfternoonModifier = true;
                        preliminaryTime = preliminaryTime.Replace("下午", " ");
                    }
                    int startRemoveFL = preliminaryTime.IndexOf("（");
                    int startRemoveHL = preliminaryTime.IndexOf("(");
                    int endRemoveFR = preliminaryTime.LastIndexOf("）");
                    int endRemoveHR = preliminaryTime.LastIndexOf(")");
                    if (startRemoveFL < 0)
                    {
                        startRemoveFL = int.MaxValue;
                    }
                    if (startRemoveHL < 0)
                    {
                        startRemoveHL = int.MaxValue;
                    }
                    if (endRemoveHR < 0)
                    {
                        endRemoveHR = int.MaxValue;
                    }
                    if (endRemoveFR < 0)
                    {
                        endRemoveFR = int.MaxValue;
                    }
                    int startRemove = startRemoveFL > startRemoveHL ? startRemoveHL : startRemoveFL;
                    int endRemove = endRemoveHR > endRemoveFR ? endRemoveFR : endRemoveHR;
                    if (endRemove > startRemove)
                    {
                        preliminaryTime = preliminaryTime.Remove(startRemove, endRemove - startRemove + 1);
                    }
                    if (Helpers.regTime.IsMatch(preliminaryTime))
                    {
                        var match = Helpers.regTime.Match(preliminaryTime);
                        if (match.Groups[1].Value == "")
                        {
                            standarizedTimeStringBuilder.Append(implicitTimeResult);
                            standarizedTimeStringBuilder.Append("-");
                        }
                        else if (match.Groups[2].Value != "")
                        {
                            if (match.Groups[2].Value.Length != 4)
                            {
                                standarizedTimeStringBuilder.Append(implicitTimeResult);
                            }
                            else
                            {
                                standarizedTimeStringBuilder.Append(match.Groups[2].Value);
                            }
                            standarizedTimeStringBuilder.Append("-");
                        }
                        if (match.Groups[3].Value != "")
                        {
                            standarizedTimeStringBuilder.Append(match.Groups[3].Value);
                            standarizedTimeStringBuilder.Append("-");
                        }
                        if (match.Groups[4].Value != "")
                        {
                            standarizedTimeStringBuilder.Append(match.Groups[4].Value);
                            standarizedTimeStringBuilder.Append(" ");
                        }
                        int standarziedHour = 0;
                        if (match.Groups[6].Value != "")
                        {
                            standarziedHour = int.Parse(match.Groups[6].Value);
                            if (AfternoonModifier && standarziedHour < 12)
                            {
                                standarziedHour += 12;
                            }
                            standarizedTimeStringBuilder.Append(standarziedHour);

                        }
                        int standarizedMinute = 0;
                        if (match.Groups[8].Value != "")
                        {
                            standarizedTimeStringBuilder.Append(":");
                            standarizedMinute = int.Parse(match.Groups[8].Value);
                            standarizedTimeStringBuilder.Append(standarizedMinute);
                        }
                        else if (match.Groups[6].Value != "")
                        {
                            standarizedTimeStringBuilder.Append(":00");
                        }
                        try
                        {
                            DateTime startDt = DateTime.Parse(standarizedTimeStringBuilder.ToString());
                            if (liveEvent.StartTime == default(DateTime))
                            {
                                liveEvent.StartTime = startDt;
                            }
                            //  DateTime endDt = startDt.AddMinutes(syncOptions.DurationInMinutes);
                            //   liveEvent.EndTime = endDt;

                            if (DateTime.Now > startDt)
                            {
                                CriticalTerminationFlag = true;
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                if (currentRun.Replace(" ", "").Contains("地点") || currentRun.Replace(" ", "").Contains("位置"))
                {
                    int idxPlace = currentRun.IndexOf("地点");
                    int idxCurrentRun = currentRun.IndexOf("位置");
              
                    idxPlace = idxPlace == -1 ? int.MaxValue : idxPlace;
                    idxCurrentRun = idxCurrentRun == -1 ? int.MaxValue : idxCurrentRun;
                    int later = idxCurrentRun > idxPlace ? idxPlace : idxCurrentRun;
                    liveEvent.Location = currentRun.Substring(later, currentRun.Length - later).Replace("\r\n", "").Replace(" ", "");
                }
            }
            if (!eventList.Contains(liveEvent))
            {
                eventList.Add(liveEvent);
                return true;
            }
            else
            {
                return false;
            }
        }

        internal virtual bool ShouldContinuePageLoop()
        {
            if (PageURIVariantFormat == null) return false;
            else return true;
        }

        public virtual LiveEvents GenerateEventList()
        {
            LiveEvents liveEvents = new LiveEvents();
            bool shouldPageLoopContinue = false;
            for (int i = StartingPageIndex; ; i++)
            {
                var doc = GetHtmlEventList(i);
                if (doc == null)
                {
                    break;
                }
                var nodes = GetEventNode(doc);
                try
                {
                    if (System.Diagnostics.Debugger.IsAttached == false)
                    {
                        Parallel.ForEach<HtmlNode>(nodes, new Action<HtmlNode>((node) =>
                        {
                            shouldPageLoopContinue = TryParseThenAddCurrentNode(node, liveEvents);
                        }));
                    }
                    else
                    {
                        foreach (var node in nodes)
                        {
                            shouldPageLoopContinue = TryParseThenAddCurrentNode(node, liveEvents);
                        }
                    }
                }
                catch
                {
                    break;
                }
                if (ShouldContinuePageLoop() == false || shouldPageLoopContinue == false)
                {
                    break;
                }
            }
            return liveEvents;
        }

    }

    public class NKUChemEventSource : NKUEventSource
    {
        public override string Name
        {
            get
            {
                return "南开大学化学学院讲座";
            }
        }
        public override string Description
        {
            get
            {
                return "http://chem.nankai.edu.cn/ShowMore.php?class=51";
            }
        }

        public NKUChemEventSource()
        {
            base.EventCentralizedListUrl = EventCentralizedListUrl;
            base.EventCentralziedListItemXPath = EventCentralziedListXPath;
            base.TitleNodeXPath = TitleNodeXPath;
            base.FullStoryNodeXPath = FullStoryNodeXPath;
            base.ImplicitTimeXPath = ImplicitTimeXPath;
            base.PageURIVariantFormat = PageURIVariantFormat;
            RequestEncoding = "GB2312";
        }

        const string EventCentralizedListUrl = "http://chem.nankai.edu.cn/ShowMore.php?class=51";
        const string EventCentralziedListXPath = "//a[@target=\"_blank\" and @class=\"black_yellow\"]";
        const string FullStoryNodeXPath = "//td[@valign=\"top\" and @class=\"content\" and not(@background)]";
        const string TitleNodeXPath = "//strong";
        const string ImplicitTimeXPath = "//p[@align=\"center\"]";
        const string BaseAddress = "http://chem.nankai.edu.cn/";
        const string PageURIVariantFormat = null;
    }

    public class NKUMathEventSource : NKUEventSource
    {
        public override string Name
        {
            get
            {
                return "南开大学数学学院讲座";
            }
        }
        public override string Description
        {
            get
            {
                return "http://sms.nankai.edu.cn/html/kydt/all";
            }
        }
        public NKUMathEventSource()
        {
            this.EventCentralizedListUrl = "http://sms.nankai.edu.cn/html/kydt/all";
            this.EventCentralziedListItemXPath = "//*[@id=\"neirong-main\"]/div[2]/div[3]/ul/li/a";
            this.FullStoryNodeXPath = "//div[@class=\"content pti lh24\" and @style=\"padding:0 30px;\"]";
            this.TitleNodeXPath = "//h2[@class=\"fs14 bolder\"]";
            this.ImplicitTimeXPath = "//div[@class=\"tools fc2 tCenter\"]";
            this.PageURIVariantFormat = "/page{0}";
            this.StartingPageIndex = 1;
            RequestEncoding = "GB2312";
        }
    }

    public class NKUiNankaiEventSource : NKUEventSource
    {
        public override string Name
        {
            get
            {
                return "iNankai信息";
            }
        }
        public override string Description
        {
            get
            {
                return "http://ievent.nankai.edu.cn/index.php?action=&keywords=&type=3&subtype=&dur=other&page=1";
            }
        }
        public NKUiNankaiEventSource()
        {
            this.EventCentralizedListUrl = "http://ievent.nankai.edu.cn/index.php?action=&keywords=&type=3&subtype=&dur=other&";
            this.EventCentralziedListItemXPath = "//a[@class=\"card_title\" and @href]";
            this.FullStoryNodeXPath = "//div[@id=\"lecture_top_left\"]";
            this.TitleNodeXPath = "//h1[@id=\"eventTitle\"]";
            this.ImplicitTimeXPath = null;
            this.PageURIVariantFormat = "page={0}";
            this.StartingPageIndex = 1;
            RequestEncoding = "UTF-8";
        }
    }
}
